﻿using System;
using System.IO;
using System.Threading.Tasks;
using housingsafety.server.Hawk;
using housingsafety.server.Helpers;
using housingsafety.server.Models;
using housingsafety.server.Svcs;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;

namespace housingsafety.server.SvcImpls
{
    class DiskStorageProvider : IStorageProvider
    {
        private readonly IWebHostEnvironment _hostingEnvironment;
        private readonly IOptions<HawkAuthenticationOptions> hawkOptions;
        private readonly IOptions<FileStoreConfig> _fileStoreConfig;

        public DiskStorageProvider(IWebHostEnvironment hostingEnvironment
            , IOptions<HawkAuthenticationOptions> hawkOptions
            , IOptions<FileStoreConfig> fileStoreConfig)
        {
            _hostingEnvironment = hostingEnvironment;
            this.hawkOptions = hawkOptions;
            _fileStoreConfig = fileStoreConfig;
        }

        private string EnsureUploadsFolder()
        {
            string basePath1 = _hostingEnvironment.WebRootPath;
            if (Directory.Exists(_fileStoreConfig.Value.BaseDirectory))
            {
                basePath1 = _fileStoreConfig.Value.BaseDirectory;
            }

            string baseFolder = Path.Combine(basePath1, "uploads");
            Directory.CreateDirectory(baseFolder);
            return baseFolder;
        }

        private string EnsureCopysFolder()
        {
            string basePath1 = _hostingEnvironment.WebRootPath;
            if (Directory.Exists(_fileStoreConfig.Value.BaseDirectory))
            {
                basePath1 = _fileStoreConfig.Value.BaseDirectory;
            }

            string baseFolder = Path.Combine(basePath1, "copys");
            if (!Directory.Exists(baseFolder))
            {
                Directory.CreateDirectory(baseFolder);
            }

            return baseFolder;
        }

        private string GetStoreFilePath(FilePath storePath, string userName, string groupName)
        {
            string baseFolder = EnsureUploadsFolder();
            string storeFilePath = Path.Combine(baseFolder, storePath.RelativelyStorePath);
            return storeFilePath;
        }

        private string GetStoreFilePathYt(FilePath storePath, string userName, string groupName)
        {
            string baseFolder = _hostingEnvironment.WebRootPath;
            string storeFilePath = Path.Combine(baseFolder, storePath.RelativelyStorePath);
            return storeFilePath;
        }

        private string FinalFileName(DateTime dt, string objectName)
        {
            var id = SequentialGuid.SequentialGuidGenerator.Instance.NewGuid().ToString("N");
            return DiskFileStoreHelper.FinalFileName(dt, id, objectName);
        }

        private StorePath EnsureStoreFolder(DateTime dt, string userName, string groupName)
        {
            string baseFolder = EnsureUploadsFolder();
            return DiskFileStoreHelper.EnsureStoreFolder(baseFolder, dt, userName, groupName);
        }
        private StorePath EnsureStoreFolderYt(DateTime dt, string userName, string groupName)
        {
            string baseFolder = _hostingEnvironment.WebRootPath;
            return DiskFileStoreHelper.EnsureStoreFolder(baseFolder, dt, userName, groupName);
        }

        private StorePath EnsureCopyFolder(DateTime dt, string userName, string groupName)
        {
            string baseFolder = EnsureCopysFolder();
            return DiskFileStoreHelper.EnsureStoreFolder(baseFolder, dt, userName, groupName);
        }

        public string ProviderName => "Disk";

        public async Task<bool> DeleteObjectByNameAsync(FilePath storePath, string userName, string groupName)
        {
            string storeFilePath = GetStoreFilePath(storePath, userName, groupName);
            if (!File.Exists(storeFilePath))
            {
                return false;
            }

            try
            {
                File.Delete(storeFilePath);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                return false;
            }

            return await Task.FromResult(true);
        }

        public async Task<byte[]> GetObjectByteAsync(FilePath storePath, string userName, string groupName)
        {
            string storeFilePath = GetStoreFilePath(storePath, userName, groupName);
            if (!File.Exists(storeFilePath))
            {
                return new byte[0];
            }

            return await File.ReadAllBytesAsync(storeFilePath);
        }

        public async Task<Stream> GetObjectStreamAsync(FilePath storePath, string userName, string groupName)
        {
            string storeFilePath = GetStoreFilePath(storePath, userName, groupName);
            if (!File.Exists(storeFilePath))
            {
                return new MemoryStream();
            }

            return await Task.FromResult(File.Open(storeFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite));
        }

        public async Task<Stream> GetObjectStreamAsyncYt(FilePath storePath, string userName, string groupName)
        {
            string storeFilePath = GetStoreFilePathYt(storePath, userName, groupName);
            if (!File.Exists(storeFilePath))
            {
                return new MemoryStream();
            }

            return await Task.FromResult(File.Open(storeFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite));
        }

        public async Task<RespRet<FileIndex>> StoreObjectByteAsync(byte[] objectByte, string objectName, string userName, string groupName)
        {
            var dt = DateTime.Now;
            string uniqueFileName = FinalFileName(dt, objectName);
            var storeFolder = EnsureStoreFolder(dt, userName, groupName);

            string filePath = Path.Combine(storeFolder.FullFolder, uniqueFileName);
            string fileStorePath = Path.Combine(storeFolder.RelativelyFolder, uniqueFileName);
            var fileStream = new FileStream(filePath, FileMode.Create);
            await File.WriteAllBytesAsync(filePath, objectByte);
            fileStream.Flush();
            await fileStream.DisposeAsync();

            return new RespRet<FileIndex>(true, "Ok", new FileIndex(uniqueFileName, uniqueFileName, objectByte.Length)
            {
                RelativelyStorePath = fileStorePath,
                StorePath = filePath
            });
        }

        public async Task<RespRet<FileIndex>> StoreObjectStreamAsync(Stream objectStream, string objectName, string userName, string groupName)
        {
            var dt = DateTime.Now;
            string uniqueFileName = FinalFileName(dt, objectName);
            var storeFolder = EnsureStoreFolder(dt, userName, groupName);

            string filePath = Path.Combine(storeFolder.FullFolder, uniqueFileName);
            string fileStorePath = Path.Combine(storeFolder.RelativelyFolder, uniqueFileName);
            var fileStream = new FileStream(filePath, FileMode.Create);
            await objectStream.CopyToAsync(fileStream);
            fileStream.Flush();
            await fileStream.DisposeAsync();

            return new RespRet<FileIndex>(true, "Ok", new FileIndex(uniqueFileName, uniqueFileName, objectStream.Length)
            {
                RelativelyStorePath = fileStorePath,
                StorePath = filePath
            });
        }

        public async Task<RespRet<FileIndex>> StoreFormFileAsync(IFormFile formFile, string userName, string groupName)
        {
            var dt = DateTime.Now;
            string uniqueFileName = FinalFileName(dt, string.Empty);
            var storeFolder = EnsureStoreFolder(dt, userName, groupName);

            string filePath = Path.Combine(storeFolder.FullFolder, uniqueFileName+Path.GetExtension(formFile.FileName));
            string fileStorePath = Path.Combine(storeFolder.RelativelyFolder, uniqueFileName+Path.GetExtension(formFile.FileName));
            var fileStream = new FileStream(filePath, FileMode.Create);
            await formFile.CopyToAsync(fileStream);
            fileStream.Flush();
            await fileStream.DisposeAsync();

            return new RespRet<FileIndex>(true, "Ok", new FileIndex(groupName, formFile.FileName, formFile.Length)
            {
                RelativelyStorePath = fileStorePath,
                StorePath = filePath
            });
        }
        //
        public async Task<RespRet<FileIndex>> StoreFormFileAsyncYt(IFormFile formFile, string userName, string groupName)
        {

            string wwwrootPath = _hostingEnvironment.WebRootPath;
            var dt = DateTime.Now;
            //后缀
             string extension = Path.GetExtension(formFile.FileName);
            string uniqueFileName = FinalFileName(dt, string.Empty)+extension;

            var storeFolder = EnsureStoreFolderYt(dt, userName, groupName);

            string filePath = Path.Combine(storeFolder.FullFolder, uniqueFileName);
            string fileStorePath = Path.Combine(storeFolder.RelativelyFolder, uniqueFileName);
            var fileStream = new FileStream(filePath, FileMode.Create);
            await formFile.CopyToAsync(fileStream);
            fileStream.Flush();
            await fileStream.DisposeAsync();

            return new RespRet<FileIndex>(true, "Ok", new FileIndex(groupName, formFile.FileName, formFile.Length)
            {
                RelativelyStorePath = fileStorePath,
                StorePath = filePath
            });
        }

        public bool ExistFile(FilePath storePath, string userName, string groupName)
        {
            string storeFilePath = GetStoreFilePath(storePath, userName, groupName);
            return File.Exists(storeFilePath);
        }

        public bool ExistFileYt(FilePath storePath, string userName, string groupName)
        {
            string storeFilePath = GetStoreFilePathYt(storePath, userName, groupName);
            return File.Exists(storeFilePath);
        }
        public string fileurl()
        {
            string baseFolder = EnsureUploadsFolder();
            return baseFolder;
        }

        public Task<string> GetGateWayUrl(HttpContext context)
        {
            return Task.FromResult(context.GetGateWayUrl());
        }

        public Task<string> CopyObjectFile(FilePath storePath, string userName, string groupName)
        {
            string storeFilePath = GetStoreFilePath(storePath, userName, groupName);
            var copyStoreFolder = EnsureCopyFolder(DateTime.Now, userName, groupName);

            var extension = Path.GetExtension(storeFilePath);
            var copyFileName = SequentialGuid.SequentialSqlGuidGenerator.Instance.NewGuid().ToString("N");
            string copyFilePath = $"{Path.Combine(copyStoreFolder.FullFolder, copyFileName)}{extension}";

            File.Copy(storeFilePath, copyFilePath, true);
            return Task.FromResult(copyFilePath);
        }

        public Task<string> CopyObjectFile2FileStore(FilePath storePath, string userName, string groupName)
        {
            string storeFilePath = GetStoreFilePath(storePath, userName, groupName);

            if (Directory.Exists(_fileStoreConfig.Value.TiffDirectory))
            {
                string duplicateFilePath = Path.Combine(_fileStoreConfig.Value.TiffDirectory
                    , Path.GetFileName(storeFilePath));

                File.Copy(storeFilePath, duplicateFilePath, true);
                return Task.FromResult(duplicateFilePath);
            }

            return Task.FromResult(string.Empty);
        }
    }
}